﻿#region Header

// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
//     <version>$Revision: 2659 $</version>
// </file>

#endregion Header

namespace ICSharpCode.TextEditor.Document
{
    using System;
    using System.Collections.Generic;

    /// <summary>
    /// Manages the list of markers and provides ways to retrieve markers for specific positions.
    /// </summary>
    public sealed class MarkerStrategy
    {
        #region Fields

        IDocument document;
        Dictionary<int, List<TextMarker>> markersTable = new Dictionary<int, List<TextMarker>>();
        List<TextMarker> textMarker = new List<TextMarker>();

        #endregion Fields

        #region Constructors

        public MarkerStrategy(IDocument document)
        {
            this.document = document;
            document.DocumentChanged += new DocumentEventHandler(DocumentChanged);
        }

        #endregion Constructors

        #region Properties

        public IDocument Document
        {
            get {
                return document;
            }
        }

        public IEnumerable<TextMarker> TextMarker
        {
            get {
                return textMarker.AsReadOnly();
            }
        }

        #endregion Properties

        #region Methods

        public void AddMarker(TextMarker item)
        {
            markersTable.Clear();
            textMarker.Add(item);
        }

        public List<TextMarker> GetMarkers(int offset)
        {
            if (!markersTable.ContainsKey(offset)) {
                List<TextMarker> markers = new List<TextMarker>();
                for (int i = 0; i < textMarker.Count; ++i) {
                    TextMarker marker = (TextMarker)textMarker[i];
                    if (marker.Offset <= offset && offset <= marker.EndOffset) {
                        markers.Add(marker);
                    }
                }
                markersTable[offset] = markers;
            }
            return markersTable[offset];
        }

        public List<TextMarker> GetMarkers(int offset, int length)
        {
            int endOffset = offset + length - 1;
            List<TextMarker> markers = new List<TextMarker>();
            for (int i = 0; i < textMarker.Count; ++i) {
                TextMarker marker = (TextMarker)textMarker[i];
                if (// start in marker region
                    marker.Offset <= offset && offset <= marker.EndOffset ||
                    // end in marker region
                    marker.Offset <= endOffset && endOffset <= marker.EndOffset ||
                    // marker start in region
                    offset <= marker.Offset && marker.Offset <= endOffset ||
                    // marker end in region
                    offset <= marker.EndOffset && marker.EndOffset <= endOffset
                   )
                {
                    markers.Add(marker);
                }
            }
            return markers;
        }

        public List<TextMarker> GetMarkers(TextLocation position)
        {
            if (position.Y >= document.TotalNumberOfLines || position.Y < 0) {
                return new List<TextMarker>();
            }
            LineSegment segment = document.GetLineSegment(position.Y);
            return GetMarkers(segment.Offset + position.X);
        }

        public void InsertMarker(int index, TextMarker item)
        {
            markersTable.Clear();
            textMarker.Insert(index, item);
        }

        public void RemoveAll(Predicate<TextMarker> match)
        {
            markersTable.Clear();
            textMarker.RemoveAll(match);
        }

        /// <summary>
        /// newly added
        /// </summary>
        public void RemoveAll()
        {
            markersTable.Clear();
            textMarker.Clear();
        }

        public void RemoveMarker(TextMarker item)
        {
            markersTable.Clear();
            textMarker.Remove(item);
        }

        void DocumentChanged(object sender, DocumentEventArgs e)
        {
            // reset markers table
            markersTable.Clear();
            document.UpdateSegmentListOnDocumentChange(textMarker, e);
        }

        #endregion Methods
    }
}